package com.zh.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zh.common.ErrorCode;
import com.zh.constant.AttacheConstant;
import com.zh.domain.Model.FileMetadata;
import com.zh.domain.dto.attache.DeleteAttacheRequest;
import com.zh.domain.dto.attache.PageAttacheRequest;
import com.zh.domain.dto.file.UploadFileDto;
import com.zh.domain.entity.*;
import com.zh.domain.vo.attache.AttachesVo;
import com.zh.domain.vo.user.UserVO;
import com.zh.exception.ThrowUtils;
import com.zh.service.*;
import com.zh.mapper.AttachesMapper;
import com.zh.utils.MinioUtil;
import io.minio.errors.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author Administrator
 * @description 针对表【attaches】的数据库操作Service实现
 * @createDate 2025-03-04 15:51:34
 */
@Service
@Slf4j
public class AttachesServiceImpl extends ServiceImpl<AttachesMapper, Attaches>
        implements AttachesService {
    @Resource
    private UserService userService;
    @Resource
    private FileService fileService;
    @Resource
    @Lazy
    private TeamService teamService;
    @Resource
    @Lazy
    private TeamUserService teamUserService;
    @Resource
    private MessageService messageService;
    @Resource
    private ProjectService projectService;
    @Resource
    private ProjectUserService projectUserService;
    @Resource
    private ProjectDynamicsService projectDynamicsService;
    @Resource
    private MinioUtil minioUtil;

    @Override
    @Transactional
    public Boolean add(Integer type, Integer typeId, String fileName, MultipartFile file) {
        int loginId = StpUtil.getLoginIdAsInt();
        AttachesService proxy = (AttachesService) AopContext.currentProxy();
        UploadFileDto uploadFileDto = new UploadFileDto();
        uploadFileDto.setFileName(fileName);
        uploadFileDto.setFile(file);
        try {
            //1. 上传文件
            String url = fileService.saveFile(uploadFileDto);
            FileMetadata metadata = minioUtil.getFileMetaDataFromMinio(url);
            Attaches attaches = new Attaches();
            attaches.setType(type);
            attaches.setTypeId(typeId);
            attaches.setUrl(url);
            attaches.setSize(metadata.getSize());
            attaches.setExtension(metadata.getExtension());
            attaches.setName(fileName);
            attaches.setCreateAt(LocalDateTime.now());
            attaches.setCreateBy(loginId);
            attaches.setUpdateAt(LocalDateTime.now());
            attaches.setUpdateBy(loginId);
            attaches.setStatus(1);
            attaches.setDeleted(0);
            boolean saved = proxy.save(attaches);
            proxy.sendMessageOrDynamic(true, type, typeId, fileName, url);
            return saved;
        } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException |
                 NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException |
                 InternalException e) {
            log.error("附件上传失败", e);
            ThrowUtils.throwIf(true, ErrorCode.OPERATION_ERROR, "附件上传失败");
            return false;
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public void sendMessageOrDynamic(boolean isSave, Integer type, Integer typeId, String fileName, String url) {
        int loginId = StpUtil.getLoginIdAsInt();
        switch (type) {
            // 团队
            case 0: {
                //上传人信息
                UserVO userVO = userService.getUserVoById(loginId);
                //查出该团队的成员id
                LambdaQueryWrapper<TeamUser> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(TeamUser::getTeamId, typeId);
                List<TeamUser> teamUserList = teamUserService.list(queryWrapper);
                List<Integer> userIds = teamUserList.stream().map(TeamUser::getUserId).collect(Collectors.toList());
                //查出该团队信息
                Team team = teamService.getById(typeId);
                Message message = new Message();
                message.setSendId(loginId);
                String content;
                if (isSave) {
                    content = String.format("%s 上传了附件 %s 请注意查收", userVO.getName(), fileName);
                } else {
                    content = String.format("%s 删除了附件 %s ", userVO.getName(), fileName);
                }
                message.setContent(content);
                message.setCreateAt(LocalDateTime.now());
                message.setCreateBy(loginId);
                message.setUpdateAt(LocalDateTime.now());
                message.setUpdateBy(loginId);
                message.setNoticeType(0);
                message.setType(0);
                message.setParams(Map.of(
                        "teamId", typeId.toString(),
                        "payloadType", "team",
                        "title", team.getName()
                ));
                messageService.sendMessage(message, userIds);
                return;
            }
            // 项目
            case 1: {
                //上传人信息
                UserVO userVO = userService.getUserVoById(loginId);
                //向该团队添加动态
                ProjectDynamics dynamic = new ProjectDynamics();
                dynamic.setProId(typeId);
                String content;
                if (isSave) {
                    content = String.format("%s 上传了附件 %s 请注意查收", userVO.getName(), fileName);
                } else {
                    content = String.format("%s 删除了附件 %s ", userVO.getName(), fileName);
                }
                dynamic.setContent(content);
                dynamic.setCreateAt(LocalDateTime.now());
                dynamic.setCreateBy(loginId);
                dynamic.setUpdateAt(LocalDateTime.now());
                dynamic.setUpdateBy(loginId);
                projectDynamicsService.save(dynamic);
                return;
            }
            // todo 需求
            case 2: {

                return;
            }
            // todo 任务
            case 3: {

                return;
            }
            default:
        }
    }

    @Override
    @Transactional
    public Boolean deleteAttache(DeleteAttacheRequest deleteAttacheRequest) {
        AttachesService proxy = (AttachesService) AopContext.currentProxy();
        //1. 校验参数
        int loginId = StpUtil.getLoginIdAsInt();
        Integer typeId = deleteAttacheRequest.getTypeId();
        Integer type = deleteAttacheRequest.getType();
        Integer attacheId = deleteAttacheRequest.getAttacheId();
        ThrowUtils.throwIf(typeId == null || type == null || attacheId == null, ErrorCode.PARAMS_ERROR);
        ThrowUtils.throwIf(!AttacheConstant.validType(type), ErrorCode.PARAMS_ERROR, "类型错误");
        //2.权限校验 团队文档只能由团队负责人删除 项目文档只能由项目成员删除
        switch (type) {
            case 0: {
                //团队
                Team team = teamService.getById(typeId);
                ThrowUtils.throwIf(!team.getOwnerId().equals(loginId), ErrorCode.FORBIDDEN_ERROR);
                break;
            }
            case 1: {
                //项目
                LambdaQueryWrapper<ProjectUser> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(ProjectUser::getProId, typeId);
                List<ProjectUser> projectUsers = projectUserService.list(queryWrapper);
                List<Integer> userIdList = projectUsers.stream().map(ProjectUser::getUserId).collect(Collectors.toList());
                ThrowUtils.throwIf(!userIdList.contains(loginId), ErrorCode.FORBIDDEN_ERROR);
            }
        }
        //3. 删除附件
        Attaches attaches = proxy.getById(attacheId);
        boolean removed = proxy.removeById(attacheId);
        //4. 发送到对应的动态(团队发消息、项目发动态,需求、任务暂定)
        proxy.sendMessageOrDynamic(false, type, typeId, attaches.getName(), attaches.getUrl());
        //5. 去真正的删除文件
//        ThreadManager.execute(() -> {
//            DeleteFileDto deleteFileDto = new DeleteFileDto();
//            deleteFileDto.setUrl(attaches.getUrl());
//            try {
//                fileService.deleteFileByUrl(deleteFileDto);
//            } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException |
//                     NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException |
//                     InternalException e) {
//                throw new RuntimeException(e);
//            }
//        });
        return removed;
    }

    @Override
    public Page<AttachesVo> pageAttache(PageAttacheRequest pageAttacheRequest) {
        Integer type = pageAttacheRequest.getType();
        Integer typeId = pageAttacheRequest.getTypeId();
        String name = pageAttacheRequest.getName();
        ThrowUtils.throwIf(!AttacheConstant.validType(type), ErrorCode.PARAMS_ERROR, "类型错误");
        ThrowUtils.throwIf(typeId == null, ErrorCode.PARAMS_ERROR);
        pageAttacheRequest.standardizeSize();
        Integer current = pageAttacheRequest.getCurrent();
        Integer pageSize = pageAttacheRequest.getPageSize();
        //1. 分页查询 附件信息
        LambdaQueryWrapper<Attaches> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Attaches::getType, type)
                .eq(Attaches::getTypeId, typeId)
                .eq(Attaches::getDeleted, 0)
                .eq(Attaches::getStatus, 1)
                .like(null != name, Attaches::getName, name)
                .orderByDesc(Attaches::getCreateAt)
                .orderByDesc(Attaches::getUpdateAt)
                .orderByDesc(Attaches::getId);
        Page<Attaches> page = new Page<>(current, pageSize);
        Page<Attaches> attachesPage = this.page(page, queryWrapper);
        List<Attaches> records = page.getRecords();
        List<Integer> userIdList = records
                .stream()
                .map(Attaches::getCreateBy)
                .collect(Collectors.toList());
        List<UserVO> userVOList = userService.listUserVoByIds(userIdList);
        Map<Integer, UserVO> userVOMap = userVOList.stream().collect(Collectors.toMap(UserVO::getId, userVO -> userVO));
        List<AttachesVo> resultList = new ArrayList<>();
        records.forEach(attaches -> {
            AttachesVo attachesVo = BeanUtil.copyProperties(attaches, AttachesVo.class);
            UserVO userVO = userVOMap.get(attaches.getCreateBy());
            attachesVo.setUploader(userVO);
            resultList.add(attachesVo);
        });
        Page<AttachesVo> pageResult = new Page<>(current, pageSize);
        BeanUtil.copyProperties(attachesPage, pageResult);
        pageResult.setRecords(resultList);
        return pageResult;
    }


}




